﻿using System;
using System.Collections.Generic;
using System.Text;
using PostSharp.Laos;
using B4ALL.JITL.Contract;
using Spring.Context;
using Spring.Context.Support;
using B4ALL.Common;
using System.Reflection;

namespace B4ALL.JITL
{
    [Serializable()]
    public class JITLAttribute : OnMethodBoundaryAspect
    {

        public override void OnEntry(MethodExecutionEventArgs eventArgs)
        {

            JITLContext jitlContext = Context.GetContext<JITLContext>();

            IApplicationContext ctx = (IApplicationContext)ContextRegistry.GetContext();

            if (ctx.ContainsObject("JITLService"))
            {
                IJITLService jitlService = (IJITLService)ctx.GetObject("JITLService");

                if (jitlService.IsJITL(eventArgs) && (jitlContext == null || (jitlContext != null && jitlContext.DelayLoad)))
                {
                    eventArgs.ReturnValue = jitlService.NewDummyObject(eventArgs);
                    eventArgs.FlowBehavior = FlowBehavior.Return;
                }
            }
        }

        /// <summary>
        /// Checks that method that gets applied this attribute actually returns an IJITLObject
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public override bool CompileTimeValidate(System.Reflection.MethodBase method)
        {
            MethodInfo mInfo = (MethodInfo)method;

            List<Type> parameters = new List<Type>();
            foreach (ParameterInfo paramInfo in method.GetParameters())
                parameters.Add(paramInfo.GetType());

            //MethodInfo realMINfo = method.DeclaringType.UnderlyingSystemType.GetMethod(
            //    method.Name,
            //    BindingFlags.ExactBinding | BindingFlags.,
            //    null,
            //    parameters.ToArray(),
            //    null
            //    );


            //Type returnType = realMINfo.ReturnType;


            if (method.IsConstructor || method.MemberType != MemberTypes.Method || !method.IsStatic)
                throw new Exception(String.Format("Class: {0}, Method: {1}. JITLAttribute cannot be applied on constructors, GET or SET methods, non static members."));

            //if (returnType.GetCustomAttributes(typeof(JITLObjectAttribute), true).Length == 0 && returnType.GetInterface(typeof(IJITLObject).Name) == null)
            //    throw new Exception(String.Format("Class: {0}, Method: {1}. JITLAttribute cannot be applied on methods that do not return an IJITLObject (return type is {2}).", method.DeclaringType.FullName, method.Name, returnType.FullName));

            return true;
        }
    }
}